/*
 * Copyright (C) 2008 GeoScheduler Team, as stated on <http://www.geoscheduler.org/authors>.
 * 
 * This file is part of GeoScheduler.
 * 
 * GeoScheduler is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 * 
 * GeoScheduler is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU Lesser General Public License for more details.
 * 
 * You should have received a copy of the GNU Lesser General Public License
 * along with GeoScheduler. If not, see <http://www.gnu.org/licenses/>.
 */
package org.geoscheduler.model;

import org.geoscheduler.commons.marshaller.JSONField;
import org.geoscheduler.commons.tools.GeoTools;

/**
 * Table collecting physical locations for the events.
 * 
 * @author lko
 * @version $Id: Location.java 161 2008-04-09 19:02:45Z srakyi $
 */
public class Location extends VersionedEntity implements Identifiable, RemoteIdentifiable {

	private Long id;
	private Integer lat;
	private Integer lon;
	private Integer radius;
	private Integer remoteId;
	
	private boolean latSet = false;
	private int latLo;
	private int latHi;
	private int latIdx;
	
	private boolean lonSet = false;
	private int lonLo;
	private int lonHi;
	private int lonIdx;
	
	private boolean radiusSet = false;

	private int crop;

	public Location() {
		super();
	}

	public Location(Long id, int version, Integer lat, Integer lon, Integer radius, Integer remoteId) {
		super();
		this.setVersion(version);
		
		this.id = id;		
		this.lat = lat;
		this.latSet = lat != null;
		this.lon = lon;
		this.lonSet = lon != null;
		this.radius = radius;
		this.radiusSet = radius != null;
		computeLatLonIndices();
		this.remoteId = remoteId;
	}

	public Long getId() {
		return id;
	}

	public void setId(Long id) {
		this.id = id;
	}

	@JSONField
	public Integer getLon() {
		return lon;
	}

	public void setLon(Integer lon) {
		this.lon = lon;
		this.lonSet = lon != null;
		computeLatLonIndices();
	}

	@JSONField
	public Integer getLat() {
		return lat;
	}

	public void setLat(Integer lat) {
		this.lat = lat;
		this.latSet = lat != null;
		computeLatLonIndices();
	}

	@JSONField
	public Integer getRadius() {
		return radius;
	}

	public void setRadius(Integer radius) {
		this.radius = radius;
		this.radiusSet = radius != null;
		computeLatLonIndices();
	}

	@JSONField
	public Integer getRemoteId() {
		return remoteId;
	}

	public void setRemoteId(Integer remoteId) {
		this.remoteId = remoteId;
	}

	public int getLatLo() {
		return latLo;
	}

	public int getLatHi() {
		return latHi;
	}

	public int getLatIdx() {
		return latIdx;
	}

	public int getLonLo() {
		return lonLo;
	}

	public int getLonHi() {
		return lonHi;
	}

	public int getLonIdx() {
		return lonIdx;
	}

	public int getCrop() {
		return crop;
	}

	public void computeLatLonIndices() {
		if ((!latSet) || (!lonSet) || (!radiusSet)) {
			return;
		}
		
		// first find out latitude borders
		int latDist = (int)(GeoTools.getLatitudeDistanceInDegrees(this.lat, this.lon, this.radius) * 1000000);
		this.latLo = this.lat - latDist;
		this.latHi = this.lat + latDist;
		if (this.latLo % 2 == 1) {
			this.latLo ++;
		}
		if (this.latHi % 2 == 1) {
			this.latHi ++;
		}
		
		// now we're gonna find longitude borders
		int lonDist = (int)(GeoTools.getLongitudeDistanceInDegrees(this.lat, this.lon, this.radius) * 1000000);
		this.lonLo = this.lon - lonDist;
		this.lonHi = this.lon + lonDist;
		if (this.lonLo % 2 == 1) {
			this.lonLo ++;
		}
		if (this.lonHi % 2 == 1) {
			this.lonHi ++;
		}
		
		byte crop1 = 0;
		while (((this.latLo >> crop1) != (this.latHi >> crop1)) && (crop1 < 31)) {
			crop1 ++;
		}
		
		byte crop2 = 0;
		while (((this.lonLo >> crop2) != (this.lonHi >> crop2)) && (crop2 < 31)) {
			crop2 ++;
		}
		
		this.crop = crop1 > crop2 ? crop1 : crop2;
		
		this.latIdx = (this.latLo >> this.crop);// << this.crop);
		this.lonIdx = (this.lonLo >> this.crop);// << this.crop);
	}

}